package com.bird.thread.base.thread;

/**
 * @author: bird
 * @Data: 2021/6/30 15:13
 * @description: 3个线程 线程1和线程2首先被阻塞. 线程3唤醒它们。使用 notify,notifyAll().
 * start先执行并不代表线程先启动。
 */
public class WaitNotifyAll implements Runnable {

    // 定义一个资源对象锁
    private static final Object resourceA = new Object();


    public static void main(String[] args) throws InterruptedException {
        Runnable r = new WaitNotifyAll();
        Thread threadA = new Thread(r);
        Thread threadB = new Thread(r);
        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {

                    // 一个线程调用这个对象的notifyAll()方法,那么和这个对象的相关的线程都将被唤醒。
                    resourceA.notifyAll();

                    // 这个只会唤醒 其中一个线程。唤醒是随机的。其它的阻塞的线程还是继续等待被唤醒。
                    // resourceA.notify();
                    System.out.println("ThreadC notified.");
                }
            }
        });

        threadA.start();
        threadB.start();
        Thread.sleep(200);// wait 要发生在 thread-c之前
        threadC.start();
    }


    @Override
    public void run() {
        synchronized (resourceA) {
            System.out.println(Thread.currentThread().getName() + " 获取到了资源锁");
            try {
                System.out.println(Thread.currentThread().getName() + " waits to start.");
                // 调用这个对象锁的wait()方法,线程将会阻塞，等待被唤醒。
                // 让获取到这个资源锁的线程,进入阻塞状态 并释放了资源锁 等待被唤醒之后 再重新的争抢锁。
                resourceA.wait();
                System.out.println(Thread.currentThread().getName() + " 等待结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /*
     * 总结：
     * 1：如果一个线程调用对象锁的wait()方法 说明这个线程将会进入阻塞，等待被唤醒。且释放锁资源 等待被其它的线程唤醒之后再次争取锁资源。
     * 2：如果一个线程调用对象锁的notifyAll()方法 那么和这个对象锁相关的被阻塞的线程都将被唤醒,然后重新争取锁资源。
     * 3：如果一个线程调用对象锁的notify()方法,那么和这个对象锁相关的被阻塞的线程只能有一个线程被唤醒 其它的线程继续阻塞状态。
     *    等待被其它的线程调用对象锁的notifyAll()唤醒。
     */
}
